#pragma once

struct IDirect3DTexture9;
struct IWMProfile;
struct IXAudio2SourceVoice;

class UIRenderer;

class UIVideo: public AVUI::IClientMediaElement
{
    friend class UIRenderer;
public:
    UIVideo(UIRenderer* pRenderer, const WCHAR* wzFileName);
    ~UIVideo();

    IDirect3DTexture9* GetTexture();

    virtual void Destroy();

    void Cleanup();
    void Initialize();

    virtual void set_Volume(float volume);

    void Update(); 

private:
    void MainSampleRetrieved(DWORD dwDuration);
    void AllocateBuffers();
    void PostNextBuffer();

    enum QueueItemType
    {
        None,
        QueueItemTypeVideoParams,
        QueueItemTypeVideoSampleBuffer,
        QueueItemTypeSampleRetrieved,
        QueueItemTypeAudioSampleRetrieved,
        QueueItemTypeShutdown
    };

    struct QueueItem
    {
        QueueItem(QueueItemType inType) : type(inType), cbSize(sizeof(QueueItem)) { }
        QueueItemType type;
        int cbSize;        
    };

    struct QueueItemVideoParams : QueueItem
    {
        QueueItemVideoParams(int inWidth, int inHeight, WAVEFORMATEX* inpWaveFormat) : QueueItem(QueueItemTypeVideoParams), width(inWidth), height(inHeight), WaveFormat(*inpWaveFormat) { cbSize = sizeof(QueueItemVideoParams); }
        int width;
        int height;
        WAVEFORMATEX WaveFormat;
    };

    struct QueueItemVideoSampleBuffer : QueueItem
    {
        QueueItemVideoSampleBuffer(void* inpBits, int inPitch) : QueueItem(QueueItemTypeVideoSampleBuffer), pBits(inpBits), Pitch(inPitch) { cbSize = sizeof(QueueItemVideoSampleBuffer); }
        void* pBits;
        int Pitch;
    };

    struct QueueItemAudioSampleRetrieved : QueueItem
    {
        QueueItemAudioSampleRetrieved(BYTE* inpData, int inCb) : QueueItem(QueueItemTypeAudioSampleRetrieved), pData(inpData), cb(inCb) { cbSize = sizeof(QueueItemAudioSampleRetrieved); }
        BYTE* pData;
        int cb;
    };

    struct QueueItemSampleRetrieved : QueueItem
    {
        QueueItemSampleRetrieved(DWORD inSampleDuration) : QueueItem(QueueItemTypeSampleRetrieved), SampleDuration(inSampleDuration) { cbSize = sizeof(QueueItemSampleRetrieved); }
        DWORD SampleDuration;
    };


    void BeginUIVideoThreadProcessQueue();
    QueueItem* GetNextUIVideoThreadQueueItem(QueueItem* pQueueItemLast);
    void PostUIVideoThreadQueueItem(QueueItem* pQueueItem);
    void EndUIVideoThreadProcessQueue();

    void BeginMainProcessQueue() { BeginUIVideoThreadProcessQueue(); }
    QueueItem* GetNextMainQueueItem(QueueItem* pQueueItemLast);
    void PostMainQueueItem(QueueItem* pQueueItem);
    void EndMainProcessQueue();

    static unsigned long __stdcall UIVideoThreadBeginStatic(void* pvArgument) { return ((UIVideo*)pvArgument)->UIVideoThreadBegin(); }
    unsigned int UIVideoThreadBegin();
    HRESULT GetStreamNumbers(IWMProfile* pProfile, WORD* pwVideoStream, WORD* pwAudioStream);

    void DeviceLost();
    void DeviceReset();

    UIRenderer*          m_pRenderer;
    unsigned int m_imageWidth;
    unsigned int m_imageHeight;
    WAVEFORMATEX m_waveFormat;
    HANDLE m_hVideoThread;

    float m_volume;

    CRITICAL_SECTION m_cs;

    WCHAR m_wzFileName[256];

    IDirect3DTexture9* m_pTexture;

    AVUI::ItemStructList<char> m_mainThreadQueue;
    AVUI::ItemStructList<char> m_uiVideoThreadQueue;
    void* m_rgUIVideoBuffers[2];
    int m_rgUIVideoBufferPitch[2];

    HANDLE m_hQueuedItemsEvent;

    IDirect3DTexture9* m_rgTextures[2];
    IDirect3DSurface9* m_rgSurfaces[2];

    int m_iCurrentTexture;
    bool m_isPostPending;
    DWORD m_dwSampleTime;

    DWORD m_dwDuration;
    DWORD m_dwDurationPending;

    IXAudio2SourceVoice* m_pSourceVoice;
};

